package com.yike.user.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yike.common.base.BaseServiceImpl;
import com.yike.common.constant.CommonConstant;
import com.yike.common.exception.BusinessException;
import com.yike.common.pagination.PageInfo;
import com.yike.common.pagination.Paging;
import com.yike.common.redis.RedisUtil;
import com.yike.common.tool.CommonUtil;
import com.yike.common.tool.LoginUtil;
import com.yike.common.tool.StringUtil;
import com.yike.user.entity.*;
import com.yike.user.mapper.*;
import com.yike.user.param.*;
import com.yike.user.service.PlatformWithdrawalService;
import com.yike.user.utils.AlipayTransferUtil;
import com.yike.user.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 代理商提现申请表 服务实现类
 *
 * @author Sakura
 * @since 2024-09-23
 */
@Slf4j
@Service
public class PlatformWithdrawalServiceImpl extends BaseServiceImpl<AgentWithdrawalApplyMapper, AgentWithdrawalApply> implements PlatformWithdrawalService {

    @Autowired
    private AgentWithdrawalApplyMapper agentWithdrawalApplyMapper;
    @Autowired
    private AgentCommissionMapper agentCommissionMapper;
    @Autowired
    private AgentWithdrawalRecordMapper agentWithdrawalRecordMapper;
    @Autowired
    private UserBankAccountMapper userBankAccountMapper;
    @Autowired
    private CommonUtil commonUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AlipayTransferUtil alipayTransferUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysSettingMapper sysSettingMapper;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public String getWithdrawalRate() throws Exception {
        // 获取系统费率配置信息
        SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.lambdaQuery(SysSetting.class)
                .eq(SysSetting::getKeyName, "agent_withdrawal_rate"));
        if (sysSetting == null) {
            sysSetting = new SysSetting();
            sysSetting.setKeyName("agent_withdrawal_rate");
            sysSetting.setValue("1");
            sysSetting.setCreateBy(LoginUtil.getUserId());
            sysSettingMapper.insert(sysSetting);
        }
        return sysSetting.getValue();
    }

    @Override
    public boolean setWithdrawalRate(SetWithdrawalParam setWithdrawalParam) throws Exception {
        // 获取系统费率配置信息
        SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.lambdaQuery(SysSetting.class)
                .eq(SysSetting::getKeyName, "agent_withdrawal_rate"));
        if (sysSetting == null) {
            sysSetting = new SysSetting();
            sysSetting.setKeyName("agent_withdrawal_rate");
            sysSetting.setValue(setWithdrawalParam.getRate().toString());
            sysSetting.setCreateBy(LoginUtil.getUserId());
            sysSettingMapper.insert(sysSetting);
        } else {
            sysSetting.setValue(setWithdrawalParam.getRate().toString());
            sysSetting.setUpdateBy(LoginUtil.getUserId());
            sysSettingMapper.updateById(sysSetting);
        }
        return true;
    }


    @Override
    //@Transactional
    public boolean withdrawalCheck(AgentWithdrawalCheckParam agentWithdrawalCheckParam) throws Exception {
        // 通过redis防止重复提交
        if (redisUtil.hasKey(CommonConstant.AGENT_WITHDRAWAL_CHECK + agentWithdrawalCheckParam.getApplyId())) {
            throw new BusinessException(500, "请勿重复提交");
        }
        redisUtil.set(CommonConstant.AGENT_WITHDRAWAL_CHECK + agentWithdrawalCheckParam.getApplyId(), 1, 5);

        // 先判断申请信息是否正常
        AgentWithdrawalApply agentWithdrawalApply = agentWithdrawalApplyMapper.selectById(agentWithdrawalCheckParam.getApplyId());
        if (agentWithdrawalApply == null) {
            throw new BusinessException("申请信息异常");
        }
        if (agentWithdrawalApply.getStatus() != 0) {
            throw new BusinessException("申请状态异常");
        }

        // 审核通过后直接调用提现接口
        if (agentWithdrawalCheckParam.getCheckStatus() == 1) {
            // 通过Redisson配置分布式全局锁保证数据安全性
            RLock stockLock = redissonClient.getLock("redisson_check_agent_withdrawal_" + agentWithdrawalApply.getAgentId());
            try {
                //尝试加锁, 最多等待3秒, 10秒后自动解锁
                boolean getStockLock = stockLock.tryLock(3, 10, TimeUnit.SECONDS);
                if (getStockLock) {
                    // 获取当前代理商分佣信息，判断金额是否足够分润
                    AgentCommission agentCommission = agentCommissionMapper.selectOne(Wrappers.lambdaQuery(AgentCommission.class)
                            .eq(AgentCommission::getAgentId, agentWithdrawalApply.getAgentId()));
                    if (agentCommission == null || agentCommission.getWithdrawableAmount().compareTo(agentWithdrawalApply.getAmount()) < 0) {
                        throw new BusinessException("可提现金额不足");
                    }
//                    // 获取系统配置
//                    SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.lambdaQuery(SysSetting.class)
//                            .eq(SysSetting::getKeyName, "agent_withdrawal_rate"));
//                    if (sysSetting == null) {
//                        throw new BusinessException("系统配置信息异常");
//                    }

                    // 如果是审核通过需要计算手续费等问题
//                    if (agentWithdrawalCheckParam.getCheckStatus() == 1) {
//                        // 判断剩余金额是否大于手续费，如果剩余金额大于手续费就从剩余金额扣手续费，不够则直接从提现金额里面扣手续费
//                        // 将金额百分比转为 1.xx 格式，比如 10% 就是 1.10
//                        BigDecimal withdrawalFactor = new BigDecimal(sysSetting.getValue()).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP);
//
//
//                        // 计算手续费，并保留两位小数
//                        BigDecimal commissionAmount = agentWithdrawalApply.getAmount().multiply(withdrawalFactor).setScale(2, RoundingMode.HALF_UP);
//                        agentWithdrawalApply.setCommissionAmount(commissionAmount);
//
//                        // 判断剩余金额是否大于手续费
//                        BigDecimal remainingAmount = agentCommission.getWithdrawableAmount().subtract(agentWithdrawalApply.getAmount());
//                        // 计算剩余金额和实际提现金额
//                        if (remainingAmount.compareTo(commissionAmount) < 0) {
//                            // 剩余金额不够手续费的话则扣光剩余金额然后再从提现金额扣
//                            agentWithdrawalApply.setRealityAmount(agentCommission.getWithdrawableAmount().subtract(commissionAmount));
//                            agentWithdrawalApply.setResidueAmount(BigDecimal.ZERO);
//                        } else {
//                            // 剩余金额足够手续费则直接从剩余金额扣
//                            agentWithdrawalApply.setRealityAmount(agentWithdrawalApply.getAmount());
//                            agentWithdrawalApply.setResidueAmount(remainingAmount.subtract(commissionAmount));
//                        }
//                    }

                    String result = "";
                    if (agentWithdrawalApply.getType() == 1) {
                        // 1是支付宝提现
                        log.info("调用支付宝提现接口+++++++++++++++++");
                        result = alipayTransferUtil.transfer(StringUtil.getStrNo(),
                                agentWithdrawalApply.getRealityAmount(), agentWithdrawalApply.getAccount(),
                                agentWithdrawalApply.getUserName(), "代理商分佣提现");
                        log.info("支付宝提现结果：" + result);
                    }

                    if ("ok".equals(result)) {
                        agentWithdrawalApply.setStatus(3);
                        agentWithdrawalApplyMapper.updateById(agentWithdrawalApply);

                        agentCommission.setWithdrawableAmount(agentWithdrawalApply.getResidueAmount());
                        agentCommissionMapper.updateById(agentCommission);
                    } else {
                        agentWithdrawalApply.setStatus(4);
                        agentWithdrawalApply.setErrorRemark(result);
                        agentWithdrawalApply.setUpdateTime(new Date());
                        agentWithdrawalApplyMapper.updateById(agentWithdrawalApply);

                        // 这里其实可以选择不泡异常直接保存失败原因的
                        throw new BusinessException(result);
                    }
                }
            } catch (BusinessException e) {
                log.error("代理商提现接口逻辑异常：" + e.getMessage());
                throw new BusinessException(500, e.getMessage());
            } catch (Exception e) {
                log.error("代理商提现接口异常：" + e.getMessage(), e);
                throw new BusinessException(500, e.getMessage());
            } finally {
                //解锁
                if (stockLock.isLocked() && stockLock.isHeldByCurrentThread()) {
                    stockLock.unlock();
                }
            }
        } else {
            // 更新申请状态
            agentWithdrawalApply.setErrorRemark(agentWithdrawalCheckParam.getRemark());
            agentWithdrawalApply.setStatus(agentWithdrawalCheckParam.getCheckStatus());
            agentWithdrawalApply.setUpdateTime(new Date());
            agentWithdrawalApplyMapper.updateById(agentWithdrawalApply);
        }

        // 添加一条记录
        AgentWithdrawalRecord agentWithdrawalRecord = new AgentWithdrawalRecord();
        agentWithdrawalRecord.setApplyId(agentWithdrawalCheckParam.getApplyId());
        agentWithdrawalRecord.setUserId(LoginUtil.getUserId());
        agentWithdrawalRecord.setRemark(agentWithdrawalCheckParam.getRemark());
        if (agentWithdrawalCheckParam.getCheckStatus() == 1) {
            agentWithdrawalRecord.setDescription(LoginUtil.getUserName() + " 通过了提现申请");
        } else {
            agentWithdrawalRecord.setDescription(LoginUtil.getUserName() + " 拒绝了提现申请");
        }
        agentWithdrawalRecordMapper.insert(agentWithdrawalRecord);

        return true;
    }

    @Override
    public boolean batchCheck(BatchWithdrawalCheckParam batchWithdrawalCheckParam) throws Exception {
        // 这里循环调用上面的审核方法就好了
        for (Long applyId : batchWithdrawalCheckParam.getApplyIds()) {
            AgentWithdrawalCheckParam agentWithdrawalCheckParam = new AgentWithdrawalCheckParam();
            agentWithdrawalCheckParam.setApplyId(applyId);
            agentWithdrawalCheckParam.setCheckStatus(batchWithdrawalCheckParam.getCheckStatus());
            agentWithdrawalCheckParam.setRemark(batchWithdrawalCheckParam.getRemark());
            withdrawalCheck(agentWithdrawalCheckParam);
        }
        return true;
    }

    @Override
    public PlatformWithdrawalApplyVo getPlatformWithdrawalApply(Long id) throws Exception {
        // 此处需要添加判断，比如只有发起人和审核人可查看详情
        return agentWithdrawalApplyMapper.getPlatformWithdrawalApply(id);
    }

    @Override
    public Paging<PlatformWithdrawalApplyVo> getPlatformWithdrawalApplyPageList(PlatformWithdrawalApplyPageParam platformWithdrawalApplyPageParam) throws Exception {
        Page<AgentWithdrawalApply> page = new PageInfo<>(platformWithdrawalApplyPageParam);
        IPage<PlatformWithdrawalApplyVo> iPage = agentWithdrawalApplyMapper.selectPlatformWithdrawalApplyList(page, platformWithdrawalApplyPageParam);
        return new Paging<PlatformWithdrawalApplyVo>(iPage);
    }

    @Override
    public Paging<PlatformWithdrawalVo> getWithdrawalAccountList(PlatformWithdrawalPageParam platformWithdrawalPageParam) throws Exception {
        Page<AgentWithdrawalApply> page = new PageInfo<>(platformWithdrawalPageParam);
        IPage<PlatformWithdrawalVo> iPage = agentWithdrawalApplyMapper.getWithdrawalAccountList(page, platformWithdrawalPageParam);
        return new Paging<PlatformWithdrawalVo>(iPage);
    }

    @Override
    public PlatformWithdrawalVo getWithdrawalInfo(Long id) throws Exception {
        return agentWithdrawalApplyMapper.getPlatformWithdrawalVo(id);
    }

}
